りおんクロニクル


C# × テスト(xUnit / MSTest / Moq)|単体テスト・モック・実務パターン総まとめ【2026年版】

Home【2026年版】C# / .NET入門と実践ガイド|基礎・業務アプリ開発・SQLite連携まで体系的に解説

C#で業務アプリを作るなら、 単体テスト(ユニットテスト) を書いておくと、 改修・リファクタリング・バグ修正のたびに安心感がまったく違います。 この記事では xUnit / MSTest / Moq を軸に、 現場で使うテストの“実務パターン”をまとめます。

この記事でわかること
・xUnit / MSTest の違いと選び方
・テストプロジェクトの作り方
・基本的なテストの書き方
・Moqで依存オブジェクトをモックする方法
・非同期メソッドのテスト
・例外テスト・境界値テスト
・サービス層・リポジトリ層のテストパターン

1. xUnit と MSTest のざっくり比較

項目xUnitMSTest
属性[Fact] / [Theory][TestMethod] / [DataTestMethod]
人気・情報量◎(OSS界隈で主流)○(Microsoft公式)
特徴シンプル・拡張性高いVisual Studioとの親和性◎

どちらでもOK ですが、 新規なら xUnit を選ぶケースが増えています。

2. テストプロジェクトの作り方

■ 2-1. xUnit の場合

dotnet new xunit -n MyApp.Tests
dotnet add MyApp.Tests reference MyApp

■ 2-2. MSTest の場合

dotnet new mstest -n MyApp.Tests
dotnet add MyApp.Tests reference MyApp

テストプロジェクトから、テスト対象プロジェクト(本体)に参照を追加します。

3. xUnit の基本([Fact] / [Theory])

■ 3-1. 単純なテスト([Fact])

public class CalculatorTests
{
    [Fact]
    public void Add_1_and_2_returns_3()
    {
        var calc = new Calculator();

        var result = calc.Add(1, 2);

        Assert.Equal(3, result);
    }
}

■ 3-2. パラメータ付きテスト([Theory])

public class CalculatorTheoryTests
{
    [Theory]
    [InlineData(1, 2, 3)]
    [InlineData(10, 5, 15)]
    [InlineData(-1, 1, 0)]
    public void Add_returns_expected(int a, int b, int expected)
    {
        var calc = new Calculator();

        var result = calc.Add(a, b);

        Assert.Equal(expected, result);
    }
}

同じロジックを複数パターンで検証できます。

4. MSTest の基本([TestMethod])

■ 4-1. 単純なテスト

[TestClass]
public class CalculatorTests
{
    [TestMethod]
    public void Add_1_and_2_returns_3()
    {
        var calc = new Calculator();

        var result = calc.Add(1, 2);

        Assert.AreEqual(3, result);
    }
}

■ 4-2. データ駆動テスト

[DataTestMethod]
[DataRow(1, 2, 3)]
[DataRow(10, 5, 15)]
public void Add_returns_expected(int a, int b, int expected)
{
    var calc = new Calculator();
    var result = calc.Add(a, b);
    Assert.AreEqual(expected, result);
}

5. Moq で依存オブジェクトをモックする

■ 5-1. パッケージ追加

dotnet add MyApp.Tests package Moq

■ 5-2. サービスがリポジトリに依存している例

public interface IUserRepository
{
    Task<User?> FindAsync(int id);
}

public class UserService
{
    private readonly IUserRepository _repo;
    public UserService(IUserRepository repo) { _repo = repo; }

    public async Task<string> GetUserNameAsync(int id)
    {
        var user = await _repo.FindAsync(id);
        return user?.Name ?? "不明";
    }
}

■ 5-3. Moqでリポジトリをモックしてテスト

public class UserServiceTests
{
    [Fact]
    public async Task GetUserNameAsync_returns_name_when_found()
    {
        var mock = new Mock<IUserRepository>();
        mock.Setup(x => x.FindAsync(1))
            .ReturnsAsync(new User(1, "Taro"));

        var service = new UserService(mock.Object);

        var name = await service.GetUserNameAsync(1);

        Assert.Equal("Taro", name);
    }
}

DBに接続せず、サービスのロジックだけを検証できます。

6. 非同期メソッドのテスト

■ 6-1. async Task をそのままテスト

[Fact]
public async Task LoadAsync_sets_flag()
{
    var vm = new MyViewModel();

    await vm.LoadAsync();

    Assert.True(vm.IsLoaded);
}

テストメソッドも async Task にするのがポイントです。

7. 例外テスト(エラーケースの検証)

■ 7-1. xUnit の場合

[Fact]
public void Create_throws_when_amount_is_negative()
{
    Assert.Throws<ArgumentException>(() =>
    {
        new Order(-1);
    });
}

■ 7-2. MSTest の場合

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void Create_throws_when_amount_is_negative()
{
    new Order(-1);
}

業務アプリでは「エラー時に例外を投げる」パターンも必ずテストしておきます。

8. サービス層のテストパターン

■ 8-1. 正常系+異常系をセットで書く

■ 8-2. 依存先はすべてモック

「外部と通信するもの」はすべてモックにして、 サービスのロジックだけを検証します。

9. テストしやすい設計とのセット運用

テストしやすい構造=保守しやすい構造です。

10. 業務アプリ向けベストプラクティス

まとめ:C#のテストは“xUnit / MSTest × Moq × DI”で一気に実務レベルになる

「テストを書きたいけど、どこから手を付ければいいか分からない」 という状態でも、 この記事のパターンをそのまま真似すれば、 C# × テスト(xUnit / MSTest / Moq)を実務レベルで回せるようになります。

前のページ 最終ページ